package Thread;

public class synchronizedDemo2 {
    public static void main(String[] args) {
        Shop s = new Shop();
        Shop s1 = new Shop();
        Shop s2 = new Shop();
        Thread t1 = new Thread("李佳源") {
            @Override
            public void run() {
                s.buy();
                //s1.buy(); //购买衣服的方法
            }
        };

        Thread t2 = new Thread("胖大星") {
            @Override
            public void run() {
                s.buy();
                //s2.buy(); //同样调用购买衣服的方法
            }
        };

        t1.start();
        t2.start();
    }
}

class Shop {
    /*
     * 当方法使用synchronized关键字修饰时，此方法在被一个线程使用时就相当于单独服务现在使用它的线程
     *
     *  例如下方 因为整个方法都使用了synchronized关键字修饰，
     *  所以buy()这个方法不同的线程在使用时都需要排队才能执行
     *  这样会减少了程序的整体运行的速率
     *  public synchronized void buy(){
     *  成员方法上的synchronized的同步监视器就是this不是不可选的
     */
    public void buy() {
        Thread thread = Thread.currentThread(); //获取当前线程的基本信息
        try {
            System.out.println(thread.getName() + ": 在选购.........");
            Thread.sleep(1000);//阻塞程序1秒

            /*
             * 当我们不再对整个方法都进行synchronized关键字修饰的时候，同样可以解决线程安全的问题
             * 我们可以将会出现线程安全问题的一段代码放入到 synchronized代码块当中，
             * 此时，放入到synchronized中的代码块，不同的线程就只能排队执行
             *
             * synchronized代码块 (同步块)
             * synchronized(同步监视器对象){}
             *
             * 同步监视器 中传入的就是线程需要上锁的实例
             * 当前程序 两个线程都是调用的s实例的buy方法 所以直接锁的就是s实例(this代表当前调用此方法的实例)
             * */
            synchronized (this) {
                System.out.println(thread.getName() + ": 在试穿///....///");
                Thread.sleep(2000);//阻塞程序1秒钟
            }

//            //当前同步监视器中传入的对象是执行到此处才new出来的对象，所以不同的线程new出来的对象是不同的
//            //所以 同步监视器中存放的通常都是 共享资源
//            // 在此处要是new出来的对象肯定是不会生效的，new出来的对象并不是共享资源，上锁后并不会被别的线程访问
//            synchronized(new Object()){
//                System.out.println(thread.getName()+":在试穿...++...");
//                Thread.sleep(2000);
//            }

            /*
             * 此时synchronized中的对象是一个字面量abc
             * 在java中String由字面量创建的值会存放在字符常量池当中.
             * 当前不管那个线程执行到了这个synchronized方法时 都是给同一个abc字面量对象的值上的锁
             * 所以字符串变量也是可以实现上锁同步(排队 不是同时)的操作
             * 但是不是一个正确的监视器 不推荐使用
             * */
//            synchronized ("abc"){
//                System.out.println(thread.getName()+":在试穿...++...");
//                Thread.sleep(2000);
//            }


            System.out.println(thread.getName() + ": 结账离开");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}
